package org.yscz.webSocket.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.yscz.common.Constants;
import org.yscz.common.ViewConfig;
import org.yscz.controller.FaceController;
import org.yscz.entity.*;
import org.yscz.entity.vo.AnswerVo;
import org.yscz.entity.vo.QuestionVo;
import org.yscz.entity.vo.RecordVo;
import org.yscz.entity.vo.ReportVo;
import org.yscz.mapper.*;
import org.yscz.media.MediaService;
import org.yscz.mqtt.MqttCustomClient;
import org.yscz.service.EvaluationService;
import org.yscz.service.impl.EvaluationServiceImpl;
import org.yscz.task.AbnormalEmotion;
import org.yscz.task.ApplicationRunnerImpl;
import org.yscz.task.ApplicationRunnerImpl.AbnormalEmotionImage;
import org.yscz.webSocket.WebSocket;
import org.yscz.webSocket.service.WebSocketService;

import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: pe
 * @description: WebSocketServiceImpl业务层实现类
 * @author: muqs
 * @create: 2021-08-26 21:02
 **/
@Service
@Slf4j
public class WebSocketServiceImpl implements WebSocketService {

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");

    public static Map uuidMap = new HashMap();

    @Autowired
    private MqttCustomClient mqttCustomClient;

    @Autowired
    private EvaluationService evaluationService;

    @Autowired
    private MediaService mediaService;

    @Resource
    private ProjectMapper projectMapper;

    @Resource
    private AnswerMapper answerMapper;

    @Resource
    private RecordMapper recordMapper;

    @Resource
    private QuestionMapper questionMapper;

    @Resource
    private ReportMapper reportMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private ScoreMapper scoreMapper;

    @Resource
    private ScaleMapper scaleMapper;

    @Value("${yscz.usbDevice.cameraUrl}")
    private String cameraUrl;

    @Value("${yscz.usbDevice.usbType}")
    private String usbType;

    @Value("${yscz.mediaServer.ip}")
    private String mediaIp;

    @Value("${yscz.mediaServer.flv-port}")
    private Integer flvPort;

    @Value("${yscz.alg.uuid}")
    private String algUuid;

    /**
     * 暂停测评关闭流媒体的uuid
     */
    public static String mediaSuspendUuid;

    /**
     * 暂停测评到第几题了
     */
    public static Integer suspendQuestionNum;

    /**
     * 拍照上传对应的流，用于拍照上传成功后关闭流
     */
    public static String mediaStartUuid;

    public static Map mediaStartMap = new HashMap();

    public static String recordUuid;

    /**
     * 继续测评题目折线图数据
     */
    public static JSONArray questJSONArray = new JSONArray();

    /**
     * 继续测评时间折线图数据
     */
    public static JSONArray timeJSONArray = new JSONArray();

    @Override
    public void processMessage(JSONObject msgObj) {

        String type = msgObj.getString("type");

        // 根据不同的消息类型处理消息
        switch (type) {
            // 蹦没蹦
            case "heartbeat":
                heartbeat(msgObj);
                break;
            // 进入测评页
            case "enter-evaluation-page":
                enterEvaluationPage(msgObj);
                break;
            // 开始答题
            case "start-answer":
                startAnswer(msgObj);
                break;
            // 上一题
            case "prev-question":
                prevQuestion(msgObj);
                break;
            // 下一题
            case "next-question":
                nextQuestion(msgObj);
                break;
            // 副屏请求暂停测评
            case "apply-suspend":
                applySuspen(msgObj);
                break;
            // 副屏取消暂停
            case "apply-suspend-cancel":
                applySuspendCancel(msgObj);
                break;
            // 主屏同意暂停测评
            case "agree-suspend":
                agreeSuspend(msgObj);
                break;
            // 主屏拒绝暂停测评
            case "disagree-suspend":
                disagreeSuspend(msgObj);
                break;
            // 结束测评
            case "submit-answer":
                submitAnswer(msgObj);
                break;
            // 拍照上传之前推送流
            case "media-start":
                mediaStart(msgObj);
                break;
            // 退出
            case "main-exit":
                mainExit(msgObj);
                break;
            // 人脸识别
            case "face-recognition-start":
                faceRecognition(msgObj);
                break;
            // 误操作关闭流媒体
            case "media-stop":
                mediaStop(msgObj);
                break;
            // 人脸识别重新启动流
            case "media-reset":
                mediaRestart(msgObj);
                break;
            // 确认暂停，退出测评
            case "exit-evaluation":
                exitEvaluation(msgObj);
                break;
        }
    }

    /**
     * 人脸识别失败没有人脸重新发送流
     */
    private void mediaRestart(JSONObject msgObj) {
        JSONObject dataObj = msgObj.getJSONObject("data");
        dataObj.put("state", true);
        //关闭之前的uuid
        String uuid = dataObj.getString("uuid");
        log.info("返回关闭流媒体uuid:[{}]", uuid);
        try {
            if (!StringUtils.isEmpty(uuid)) {
                //关闭流媒体
                mediaService.delSteam(uuid);
                mediaService.stopUsbStream();
                Thread.sleep(1500);
            }

            //重新退给前台一个新流
            String uuidNew = UUID.randomUUID().toString();
            ViewConfig.mediaStartCacheUuid = uuidNew;

            RoomBean roomBean = getRoomBean(uuidNew);

            //开始分析
            evaluationService.startEvaluation(roomBean, false);

            //JSONObject jsonObject = new JSONObject();
            dataObj.put("uuid", uuidNew);
            //rtsp流转换为.flv
            String flv = flvMethod(uuidNew, mediaIp, flvPort);
            dataObj.put("cameraUrl", flv);

            log.info("人脸识别reset之前的msgObj:[{}]", msgObj);
            //人脸识别
            new Thread(() -> {
                faceStartRecognition(msgObj, uuidNew);
            }).start();

            if (WebSocket.getMainSession() != null) {
                WebSocket.SendMessage(WebSocket.getMainSession(), writeNullValue(msgObj));
            }
        } catch (Exception e) {
            log.error("关闭流媒体异常");
        }
    }

    /**
     * 误操作关闭流媒体
     */
    private void mediaStop(JSONObject msgObj) {
        JSONObject dataObj = msgObj.getJSONObject("data");
        //最新流得uuid
        String uuid = dataObj.getString("uuid");
        log.info("返回关闭流媒体uuid:[{}]", uuid);
        try {
            //关闭流媒体
            mediaService.delSteam(uuid);
            mediaService.stopUsbStream();
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            log.error("关闭流媒体异常");
        }
    }

    /**
     * Websocket心跳
     */
    private void heartbeat(JSONObject msgObj) {
        String screenType = msgObj.getString("data");

        if ("main".equals(screenType)) {
            if (WebSocket.getMainSession() != null) {
                WebSocket.SendMessage(WebSocket.getMainSession(), writeNullValue(msgObj));
            }
        } else if ("vice".equals(screenType)) {
            if (WebSocket.getViceSession() != null) {
                WebSocket.SendMessage(WebSocket.getViceSession(), writeNullValue(msgObj));
            }
        }
    }

    /**
     * @Description: 进入测评页
     * @Param: msgObj
     * @Author: muqs
     * @Date: 2021/8/27
     */
    private void enterEvaluationPage(JSONObject msgObj) {
        JSONObject dataObj = msgObj.getJSONObject("data");

        if (dataObj != null) {

            // 获取被测人测评信息
            evaluationService.getEvalInfos(dataObj);

            // 发送消息给主副屏
            WebSocket.sendInfo(writeNullValue(msgObj));
        }
    }

    /**
     * @Description: 开始答题
     * @Author: Muqs
     * @Param: msgObj
     * @Date: 2021/8/27
     */
    private void startAnswer(JSONObject msgObj) {
        JSONObject dataObj = msgObj.getJSONObject("data");
        if (dataObj != null) {
            Long recordId = dataObj.getLong("recordId");
            ViewConfig.recordId = recordId;
            log.info("开始答题recordId:[{}]", recordId);

            // 更新测评记录信息
            Record record = recordMapper.selectById(recordId);
            log.info("开始答题record:[{}]", record);

//            if (record != null) {
//                WebSocketServiceImpl.recordUuid = record.getRecordUuid();
//            }

            // 更新开始测评时间 add by muqs
            record.setRecordStartTime(new Date());
            String recordCreatetime = StringUtils.isNotEmpty(record.getRecordCreateTime()) ? record.getRecordCreateTime() + "," + sdf.format(new Date()) : sdf.format(new Date());
            record.setRecordCreateTime(recordCreatetime);
            recordMapper.updateById(record);

            dataObj.put("recordInfo", record);

            // 查询测评记录，将试题信息同时推送给主副屏
            Map condition = new HashMap();
            condition.put("scaleId", record.getScaleIdFk());
            condition.put("questionNum", record.getQuestionNum());
            QuestionVo questionVo = questionMapper.queryDetailById(condition);

            // 将试题信息推送给主副屏
            dataObj.put("questionInfo", questionVo);

            // 将答题信息推送给主副屏
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("question_id_fk", questionVo.getQuestionId());
            queryWrapper.eq("record_id_fk", recordId);
            Answer answer = answerMapper.selectOne(queryWrapper);
            dataObj.put("answer", answer);

            //by achen
            //通知主屏视频流
            String uuid = null;
            if (StringUtils.isEmpty(record.getRecordUuid())) {

                uuid = UUID.randomUUID().toString();
            } else {
                uuid = record.getRecordUuid();
            }
            log.info("开始答题uuid:[{}]", uuid);
            mediaSuspendUuid = uuid;

            RoomBean roomBean = getRoomBean(uuid);

            log.info("++++++++++++++++++++++++++++++++++++++++++++++++++++++");
            log.info("record.getRecordUuid():[{}]", record.getRecordUuid());
            if (StringUtils.isEmpty(record.getRecordUuid())) {
                log.info("开始答题更新完成之前recordUuid:[{}]", ApplicationRunnerImpl.algUuid);
                record.setRecordUuid(uuid);
                recordMapper.updateById(record);
                log.info("开始答题更新完成recordUuid:[{}]", record.getRecordUuid());
            }

            //推送继续测评的数据
            pushContinueTest(record);

            //开始分析
            evaluationService.startEvaluation(roomBean, true);

            //JSONObject jsonObject = new JSONObject();
            dataObj.put("uuid", uuid);
            //rtsp流转换为.flv
            String flv = flvMethod(uuid, mediaIp, flvPort);
            dataObj.put("cameraUrl", flv);
            // 发送消息给主副屏
            WebSocket.sendInfo(writeNullValue(msgObj));


        }
    }

    /**
     * 推送继续测评的数据
     */
    public void pushContinueTest(Record record) {
        if (record != null) {
            JSONObject dataObj = null;
            //问题折线图数据
            if (null == record.getQuestionLine()) {
                dataObj = new JSONObject();
                JSONArray jsonArray = new JSONArray();
                questJSONArray = jsonArray;
                dataObj.put("type", "quest-line");
                dataObj.put("data", jsonArray);
                log.info("继续测评questionLine：[{}]", jsonArray);
                if (WebSocket.getMainSession() != null) {
                    WebSocket.SendMessage(WebSocket.getMainSession(), JSONObject.toJSONString(dataObj, SerializerFeature.WriteMapNullValue));
                }
            } else {
                dataObj = new JSONObject();
                String questionLine = record.getQuestionLine();
                dataObj.put("questionLine", questionLine);
                log.info("继续测评questionLine：[{}]", JSONObject.parseArray(questionLine));
                dataObj.put("type", "quest-line");
                JSONArray jsonArray = JSONObject.parseArray(questionLine);
                //答题题号
                int size = jsonArray.size();
                JSONObject jsonObject = jsonArray.getJSONObject(size - 1);
                log.info("上一题jsonObject.getIntValue('questionIndex'):[{}]", jsonObject.get("questionIndex"));
                ViewConfig.currentQuestIndex.set(size);
                ViewConfig.everyQuestionExceptionNum.set((Integer) jsonObject.get("exceptionFaceNum"));
                //防止继续推送数据
                //questJSONArray = jsonArray; //[{"index":1,"number":1},{"index":2,"number":2},{"index":3,"number":3}]
                dataObj.put("data", jsonArray);
                log.info("继续测评questionLine：[{}]", jsonArray);
                if (WebSocket.getMainSession() != null) {
                    WebSocket.SendMessage(WebSocket.getMainSession(), JSONObject.toJSONString(dataObj, SerializerFeature.WriteMapNullValue));
                }
                //推送完之后清空
                //questJSONArray.clear();
            }
            //时间折线图数据
            if (null == record.getTimeLine()) {
                dataObj = new JSONObject();
                JSONArray jsonArray = new JSONArray();
                timeJSONArray = jsonArray;
                log.info("继续测评timeLine：[{}]", jsonArray);
                dataObj.put("type", "time-line");
                dataObj.put("data", jsonArray);
                if (WebSocket.getMainSession() != null) {
                    WebSocket.SendMessage(WebSocket.getMainSession(), JSONObject.toJSONString(dataObj, SerializerFeature.WriteMapNullValue));
                }
            } else {
                dataObj = new JSONObject();
                String timeLine = record.getTimeLine();
                log.info("继续测评timeLine：[{}]", JSONObject.parseArray(timeLine));
                dataObj.put("type", "time-line");
                JSONArray jsonArray = JSONObject.parseArray(timeLine);
                //数组最大下标 获取最大下标对应的分钟数
                int index = jsonArray.size() - 1;
                ViewConfig.minuteNum.set((int) jsonArray.getJSONObject(index).get("minuteNum"));
                ViewConfig.everyMinuteExceptionNum.set((int) jsonArray.getJSONObject(index).get("everyMinuteExceptionNum"));
                //timeJSONArray = jsonArray;
                dataObj.put("data", jsonArray);
                if (WebSocket.getMainSession() != null) {
                    WebSocket.SendMessage(WebSocket.getMainSession(), JSONObject.toJSONString(dataObj, SerializerFeature.WriteMapNullValue));
                }
            }
            //异常表情总次数、异常总答题数
            if (null == record.getExceptionSumNum() && null == record.getExceptionQuestionSumNum()) {
                dataObj = new JSONObject();
                Map<String, Object> map = new HashMap<>();
                map.put("exceptionFaceNum", ViewConfig.exceptionEmotionTotalNum.get());
                map.put("exceptionQuestionNum", ViewConfig.exceptionQuestionTotalNum.get());

                dataObj.put("type", "realTime-push");
                dataObj.put("data", map);
                if (WebSocket.getMainSession() != null) {
                    WebSocket.SendMessage(WebSocket.getMainSession(), JSONObject.toJSONString(dataObj, SerializerFeature.WriteMapNullValue));
                }
            } else {
                dataObj = new JSONObject();
                Integer exceptionSumNum = record.getExceptionSumNum();
                ViewConfig.exceptionEmotionTotalNum.set(exceptionSumNum);
                Integer exceptionQuestionSumNum = record.getExceptionQuestionSumNum();
                ViewConfig.exceptionQuestionTotalNum.set(exceptionQuestionSumNum);

                Map<String, Object> map = new HashMap<>();
                map.put("exceptionFaceNum", ViewConfig.exceptionEmotionTotalNum.get());
                map.put("exceptionQuestionNum", ViewConfig.exceptionQuestionTotalNum.get());

                dataObj.put("type", "realTime-push");
                dataObj.put("data", map);
                if (WebSocket.getMainSession() != null) {
                    WebSocket.SendMessage(WebSocket.getMainSession(), JSONObject.toJSONString(dataObj, SerializerFeature.WriteMapNullValue));
                }
            }
        }
    }

    /**
     * @Description: 上一题
     * @Author: Muqs
     * @Param: msgObj
     * @Date: 2021/8/27
     */
    private void prevQuestion(JSONObject msgObj) {
        ViewConfig.exceptionTimeFlag = true;
        // 将测评记录进行更新,并将题目信息同时推送给主副屏
        JSONObject dataObj = msgObj.getJSONObject("data");
        if (dataObj != null) {
            // 上一题试题编号
            Integer previousQuestionNum = dataObj.getInteger("prevQuestionNum");
            //suspendQuestionNum = previousQuestionNum;
            // 答题记录ID
            Long recordId = dataObj.getLong("recordId");
            // 当前题试题编号
            Integer questionNum = dataObj.getInteger("questionNum");
            // 当前答题选项
            String answerType = dataObj.getString("answerType");
            // 当前答题时常
            Integer answerTime = dataObj.getInteger("answerTime");
            log.info("上一题answerTime:[{}]", answerTime);

            //答题题号
            ViewConfig.currentQuestIndex.set(previousQuestionNum);
            JSONArray jsonArray = new JSONArray();
            String questLineString = stringRedisTemplate.opsForValue().get(ApplicationRunnerImpl.algUuid + "_question");
            if (StringUtils.isNotEmpty(questLineString)) {
                jsonArray = JSON.parseArray(questLineString);
            }
            log.info("上一题jsonArray:[{}]", jsonArray);
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                log.info("上一题jsonObject.getInteger('questionIndex'):[{}]", jsonObject.getInteger("questionIndex"));
                log.info("previousQuestionNum:[{}]", previousQuestionNum);
                if (jsonObject.getInteger("questionIndex").equals(previousQuestionNum)) {
                    log.info("上一题ViewConfig.everyQuestionExceptionNum.get():[{}]", ViewConfig.everyQuestionExceptionNum.get());
                    //ViewConfig.everyQuestionExceptionNum.set(ViewConfig.everyQuestionExceptionNum.get() + jsonObject.getIntValue("exceptionFaceNum"));
                    ViewConfig.everyQuestionExceptionNum.set(jsonObject.getIntValue("exceptionFaceNum"));
                }
            }
            //测评记录ID
            ViewConfig.recordId = recordId;

            //保存测评记录下每道题的异常表情次数
            // stringRedisTemplate.opsForHash().put(String.valueOf(recordId), String.valueOf(questionNum), String.valueOf(ViewConfig.everyExceptionNum));

            if (previousQuestionNum != null) {
                // 将测评记录中当前进度更新
                Record record = recordMapper.selectById(recordId);
                record.setQuestionNum(previousQuestionNum);

                // 获取上一题题目和选项信息
                Map condition = new HashMap();
                condition.put("questionNum", previousQuestionNum);
                condition.put("scaleId", record.getScaleIdFk());
                QuestionVo questionVo = questionMapper.queryDetailById(condition);
                dataObj.put("questionInfo", questionVo);

                // 将上一题答题信息推送给主副屏
                QueryWrapper queryWrapper = new QueryWrapper();
                queryWrapper.eq("question_id_fk", questionVo.getQuestionId());
                queryWrapper.eq("record_id_fk", recordId);
                Answer answer = answerMapper.selectOne(queryWrapper);

                Project project = projectMapper.selectById(1L);

                answerMapper.updateById(answer);

                dataObj.put("answer", answer);

                recordMapper.updateById(record);
                dataObj.put("recordInfo", record);

                // 将当前答题记录保存
                QueryWrapper answerWrapper = new QueryWrapper();
                answerWrapper.eq("record_id_fk", recordId);
                answerWrapper.eq("answer_question_num", questionNum);
                Answer currentAnswer = answerMapper.selectOne(answerWrapper);
                if (currentAnswer == null) {
                    currentAnswer = new Answer();
                    currentAnswer.setRecordIdFk(recordId);
                    currentAnswer.setScaleIdFk(record.getScaleIdFk());

                    // 获取题目信息
                    Map questionParam = new HashMap();
                    questionParam.put("questionNum", questionNum);
                    questionParam.put("scaleId", record.getScaleIdFk());
                    QuestionVo currentQuestionVo = questionMapper.queryDetailById(questionParam);
                    if (currentQuestionVo != null) {
                        currentAnswer.setQuestionIdFk(currentQuestionVo.getQuestionId());
                    }
                    currentAnswer.setRecordUuidFk(record.getRecordUuid());
                }

                currentAnswer.setAnswerQuestionNum(questionNum);
                if (answerTime != null) {
                    currentAnswer.setAnswerTime(answerTime);
                }
                if (!StringUtils.isEmpty(answerType)) {
                    currentAnswer.setAnswerType(answerType);
                }

                // 当前试题答案保存
                if (currentAnswer.getAnswerId() == null) {
                    answerMapper.insert(currentAnswer);
                } else {
                    //查询答题异常表情次数
                    //String exceptionNum = (String) stringRedisTemplate.opsForHash().get(String.valueOf(recordId), String.valueOf(questionNum));
                    currentAnswer.setAnswerExceptionNum(ViewConfig.everyQuestionExceptionNum.get());

                    //是否为时间异常题目
                    if (project != null) {
                        //不是异常题目
                        if (answerTime >= (project.getTimeDown())*1000 && answerTime <= (project.getTimeUp())*1000) {
                            currentAnswer.setAnswerExceptionTime(1);
                        } else {
                            currentAnswer.setAnswerExceptionTime(0);
                        }
                    }
                    answerMapper.updateById(currentAnswer);
                }

                // 发送消息给主副屏
                WebSocket.sendInfo(writeNullValue(msgObj));
            } else {
                log.info("未获取到答题数据信息,msgObj:{}", JSONObject.toJSONString(msgObj));
            }
        } else {
            log.info("上一题参数异常,msgObj:{}", JSONObject.toJSONString(msgObj));
        }
    }

    /**
     * @Description: 下一题
     * @Author: Muqs
     * @Param: msgObj
     * @Date: 2021/8/27
     */
    private void nextQuestion(JSONObject msgObj) {
        ViewConfig.exceptionTimeFlag = true;

        // 将回答问题信息入库,如果存在则进行更新操作
        JSONObject dataObj = msgObj.getJSONObject("data");
        if (dataObj != null) {
            Long recordId = dataObj.getLong("recordId");
            Integer questionNum = dataObj.getInteger("questionNum");
            //suspendQuestionNum = questionNum;
            String answerType = dataObj.getString("answerType");
            Integer answerTime = dataObj.getInteger("answerTime");
            log.info("下一题answerTime:[{}]", answerTime);

            // 下一题试题编号
            Integer nextQuestionNum = dataObj.getInteger("nextQuestionNum");

            //测评记录ID
            ViewConfig.recordId = recordId;

            // 将测评记录中当前进度更新
            Record record = recordMapper.selectById(recordId);
            record.setQuestionNum(nextQuestionNum);

            // 当前试题答案保存
            QueryWrapper answerWrapper = new QueryWrapper();
            answerWrapper.eq("record_id_fk", recordId);
            answerWrapper.eq("answer_question_num", questionNum);
            Answer answer = answerMapper.selectOne(answerWrapper);
            log.info("next question answer: [{}]", answer);
            Project project = projectMapper.selectById(1L);
            log.info("next question project: [{}]", project);
            if (answer == null) {
                answer = new Answer();
                log.info("next question everyQuestionExceptionNum: [{}]", ViewConfig.everyQuestionExceptionNum.get());
                answer.setAnswerExceptionNum(ViewConfig.everyQuestionExceptionNum.get());
                //如果是最后一题
                QueryWrapper<Question> questionQueryWrapper = new QueryWrapper<>();
                questionQueryWrapper.eq("scale_id_fk", record.getScaleIdFk());
                Integer questionCount = questionMapper.selectCount(questionQueryWrapper);
                log.info("questionCount:[{}]", questionCount);

                //保存本道题最高异常值
                if (!CollectionUtils.isEmpty(AbnormalEmotionImage.abnormalEmotionList)) {
                    AbnormalEmotion abnormalEmotion = AbnormalEmotionImage.abnormalEmotionList.get(0);
                    answer.setAnswerExceptionMaxScore(abnormalEmotion.getImageScore());
                } else {
                    answer.setAnswerExceptionMaxScore(0);
                }

                answer.setAnswerQuestionNum(questionNum);
                if (!StringUtils.isEmpty(answerType)) {
                    answer.setAnswerType(answerType);
                }
                answer.setRecordIdFk(recordId);
                answer.setScaleIdFk(record.getScaleIdFk());
                answer.setAnswerTime(answerTime);

                // 获取题目信息
                Map questionParam = new HashMap();
                questionParam.put("questionNum", questionNum);
                questionParam.put("scaleId", record.getScaleIdFk());
                QuestionVo currentQuestionVo = questionMapper.queryDetailById(questionParam);
                if (currentQuestionVo != null) {
                    answer.setQuestionIdFk(currentQuestionVo.getQuestionId());
                }
                answer.setRecordUuidFk(record.getRecordUuid());
            }
            answer.setAnswerTime(answerTime);
            answer.setAnswerType(answerType);
            if (answer.getAnswerId() == null) {
                //是否为时间异常题目
                if (project != null) {
                    if (answerTime >= (project.getTimeDown())*1000 && answerTime <= (project.getTimeUp())*1000) {
                        answer.setAnswerExceptionTime(1); // 0-是 1-否
                    } else {
                        answer.setAnswerExceptionTime(0);
                    }
                }
                List<AbnormalEmotion> abnormalEmotionList = AbnormalEmotionImage.abnormalEmotionList;
                if (!CollectionUtils.isEmpty(abnormalEmotionList)) {
                    answer.setImageUrl(JSON.toJSONString(abnormalEmotionList));
                }
                answerMapper.insert(answer);
            } else {
                //是否为时间异常题目
                if (project != null) {
                    if (answerTime >= (project.getTimeDown())*1000 && answerTime <= (project.getTimeUp())*1000) {
                        answer.setAnswerExceptionTime(1); // 0-是 1-否
                    } else {
                        answer.setAnswerExceptionTime(0);
                    }
                }
                List<AbnormalEmotion> abnormalEmotions = AbnormalEmotionImage.rangeExceptionImages(answer.getImageUrl());
                if (!CollectionUtils.isEmpty(abnormalEmotions)) {
                    answer.setImageUrl(JSON.toJSONString(abnormalEmotions));
                    AbnormalEmotion abnormalEmotion = AbnormalEmotionImage.abnormalEmotionList.get(0);
                    answer.setAnswerExceptionMaxScore(abnormalEmotion.getImageScore());
                }
                answerMapper.updateById(answer);
            }

            AbnormalEmotionImage.abnormalEmotionList.clear();  // 清空数据

            recordMapper.updateById(record);
            dataObj.put("recordInfo", record);

            // 获取下一题题目和选项信息
            Map condition = new HashMap();
            condition.put("questionNum", nextQuestionNum);
            condition.put("scaleId", record.getScaleIdFk());
            QuestionVo questionVo = questionMapper.queryDetailById(condition);
            dataObj.put("questionInfo", questionVo);

            // 将下一题答题信息推送给主副屏
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("question_id_fk", questionVo.getQuestionId());
            queryWrapper.eq("record_id_fk", recordId);
            Answer nextAnswer = answerMapper.selectOne(queryWrapper);
            dataObj.put("answer", nextAnswer);

            // 发送消息给主副屏
            WebSocket.sendInfo(writeNullValue(msgObj));

            try {
                log.info("WebSocket sendQuestionLineException ----------------&& : [{}, {}]", EvaluationServiceImpl.NotifyAlgBusiness.getAnalyzingRoomBean().getUuid(), questionNum);
                sendQuestionLineException(EvaluationServiceImpl.NotifyAlgBusiness.getAnalyzingRoomBean().getUuid(), questionNum, false, answer);
            } catch (Exception e) {
                log.error("send question line exception:[{}]", e.getMessage());
            }
            ViewConfig.currentQuestIndex.set(nextQuestionNum);

            String questLineString = stringRedisTemplate.opsForValue().get(ApplicationRunnerImpl.algUuid + "_question");
            if (StringUtils.isNotEmpty(questLineString)) {
                JSONArray jsonArray = JSON.parseArray(questLineString);
                for (int i = 0; i < jsonArray.size(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    log.info("下一题jsonObject.getInteger('questionIndex'):[{}]", jsonObject.getInteger("questionIndex"));
                    log.info("nextQuestionNum:[{}]", nextQuestionNum);
                    if (jsonObject.getInteger("questionIndex").equals(nextQuestionNum)) {
                        log.info("下一题jsonObject.getIntValue('exceptionFaceNum'):[{}]", jsonObject.getIntValue("exceptionFaceNum"));

                        //todo
                        //ViewConfig.everyQuestionExceptionNum.set(ViewConfig.everyQuestionExceptionNum.get() + jsonObject.getIntValue("exceptionFaceNum"));
                        ViewConfig.everyQuestionExceptionNum.set(jsonObject.getIntValue("exceptionFaceNum"));
                    }
                }
            }
        }
    }

    /**
     * @Description: 副屏请求暂停测评
     * @Author: Muqs
     * @Param: msgObj
     * @Date: 2021/8/27
     */
    private void applySuspen(JSONObject msgObj) {
        // 将回答问题信息入库,如果存在则进行更新操作
        JSONObject dataObj = msgObj.getJSONObject("data");
        if (dataObj != null) {
            Long recordId = dataObj.getLong("recordId");
            Integer questionNum = dataObj.getInteger("questionNum");
            log.info("请求暂停questionNum:[{}]", questionNum); //2

            String answerType = dataObj.getString("answerType");
            Integer answerTime = dataObj.getInteger("answerTime");

            QueryWrapper answerWrapper = new QueryWrapper();
            answerWrapper.eq("record_id_fk", recordId);
            answerWrapper.eq("answer_question_num", questionNum);
            Answer answer = answerMapper.selectOne(answerWrapper);
            log.info("请求暂停answer:[{}]", answer); //null

            // 将测评记录中当前进度更新
            Record record = recordMapper.selectById(recordId);
            log.info("副屏请求暂停recordId:[{}]",record);
            try {
                Answer answer2 = null;
                sendQuestionLineException(EvaluationServiceImpl.NotifyAlgBusiness.getAnalyzingRoomBean().getUuid(), questionNum, false, answer2);
            } catch (Exception e) {
                log.error("send question line exception:[{}]", e.getMessage());
            }

            if (answer == null) {
                answer = new Answer();
                answer.setAnswerQuestionNum(questionNum);
                answer.setAnswerType(answerType);
                answer.setRecordIdFk(recordId);
                answer.setScaleIdFk(record.getScaleIdFk());

                // 获取题目信息
                Map condition = new HashMap();
                condition.put("questionNum", questionNum);
                condition.put("scaleId", record.getScaleIdFk());
                QuestionVo questionVo = questionMapper.queryDetailById(condition);
                if (questionVo != null) {
                    answer.setQuestionIdFk(questionVo.getQuestionId());
                }
                answer.setRecordUuidFk(record.getRecordUuid());
            }
            // 当前试题答案保存
            answer.setAnswerType(answerType);
            // 更新答题时间信息
            answer.setAnswerTime(answerTime);

            Project project = projectMapper.selectById(1L);
            if (answer.getAnswerId() == null) {
                //是否为时间异常题目
                //不是时间异常题目
                if (answerTime >= (project.getTimeDown())*1000 && answerTime <= (project.getTimeUp())*1000) {
                    answer.setAnswerExceptionTime(1);
                } else {
                    answer.setAnswerExceptionTime(0);
                }
                //是否为异常答题
                if (ViewConfig.everyQuestionExceptionNum.get() > 0) {
                    answer.setAnswerException(0);
                } else {
                    answer.setAnswerException(1);
                }
                //异常答题个数
                answer.setAnswerExceptionNum(ViewConfig.everyQuestionExceptionNum.get());
                log.info("请求暂停添加:[{}]", AbnormalEmotionImage.abnormalEmotionList);
                //保存本道题最高异常值
//                if (!CollectionUtils.isEmpty(AbnormalEmotionImage.abnormalEmotionList)) {
//                    AbnormalEmotion abnormalEmotion = AbnormalEmotionImage.abnormalEmotionList.get(0);
//                    answer.setAnswerExceptionMaxScore(abnormalEmotion.getImageScore());
//                } else {
//                    answer.setAnswerExceptionMaxScore(0);
//                }
                //异常图片
                List<AbnormalEmotion> abnormalEmotionList = AbnormalEmotionImage.abnormalEmotionList;
                if (!CollectionUtils.isEmpty(abnormalEmotionList)) {
                    answer.setImageUrl(JSON.toJSONString(abnormalEmotionList));
                }
                answerMapper.insert(answer);
            } else {
                //是否为时间异常题目
                //不是时间异常题目
                if (answerTime >= (project.getTimeDown())*1000 && answerTime <= (project.getTimeUp())*1000) {
                    answer.setAnswerExceptionTime(1);
                } else {
                    answer.setAnswerExceptionTime(0);
                }
                //是否为异常答题
                if (ViewConfig.everyQuestionExceptionNum.get() > 0) {
                    answer.setAnswerException(0);
                } else {
                    answer.setAnswerException(1);
                }
                //异常答题个数
                answer.setAnswerExceptionNum(ViewConfig.everyQuestionExceptionNum.get());
                log.info("请求暂停ViewConfig.everyQuestionExceptionNum.get():[{}]", ViewConfig.everyQuestionExceptionNum.get());
                log.info("请求暂停更新:[{}]", AbnormalEmotionImage.abnormalEmotionList);

                //截图及题目最高异常
                List<AbnormalEmotion> abnormalEmotions = AbnormalEmotionImage.rangeExceptionImages(answer.getImageUrl());
                if (!CollectionUtils.isEmpty(abnormalEmotions)) {
                    answer.setImageUrl(JSON.toJSONString(abnormalEmotions));
                    AbnormalEmotion abnormalEmotion = AbnormalEmotionImage.abnormalEmotionList.get(0);
                    answer.setAnswerExceptionMaxScore(abnormalEmotion.getImageScore());
                }
                answerMapper.updateById(answer);
            }

            log.info("请求暂停answer:[{}]", answer);
            record.setQuestionNum(questionNum);
            recordMapper.updateById(record);

            // 发送消息给主副屏
            WebSocket.sendInfo(writeNullValue(msgObj));
        }
    }

    /**
     * @Description: 副屏取消暂停
     * @Author: Muqs
     * @Param: msgObj
     * @Date: 2021/8/27
     */
    private void applySuspendCancel(JSONObject msgObj) {
        // 发送消息给主副屏
        WebSocket.sendInfo(writeNullValue(msgObj));
    }

    /**
     * @Description: 主屏同意暂停测评
     * @Author: Muqs
     * @Param: msgObj
     * @Date: 2021/8/27
     */
    private void agreeSuspend(JSONObject msgObj) {
        JSONObject dataObj = msgObj.getJSONObject("data");
        if (dataObj != null) {
            Long recordId = dataObj.getLong("recordId");
            // 更新测评记录暂停次数
            Record record = recordMapper.selectById(recordId);
            record.setStopNum(record.getStopNum() != null ? Integer.valueOf(record.getStopNum().intValue() + 1) : Integer.valueOf(1));

            // 将暂停时间入库，一次测评完成时间
            String recordCreatetime = record.getRecordCreateTime() + "、" + sdf.format(new Date());
            record.setRecordCreateTime(recordCreatetime);

            //achen 更新问题和折线图的数据
            //数据库录入问题折线图数据
            String questLineString = stringRedisTemplate.opsForValue().get(ApplicationRunnerImpl.algUuid + "_question");
            log.info("同意暂停questLineString：[{}]", questLineString);
            record.setQuestionLine(questLineString);
            //数据库录入时间折线图数据
            String timeLineString = stringRedisTemplate.opsForValue().get(ApplicationRunnerImpl.algUuid + "_time");
            log.info("同意暂停timeLineString：[{}]", timeLineString);
            record.setTimeLine(timeLineString);

            //更新异常表情次数和异常答题数
            record.setExceptionSumNum(ViewConfig.exceptionEmotionTotalNum.get());
            log.info("同意暂停exceptionEmotionTotalNum:[{}]", ViewConfig.exceptionEmotionTotalNum.get());
            record.setExceptionQuestionSumNum(ViewConfig.exceptionQuestionTotalNum.get());
            log.info("同意暂停exceptionQuestionTotalNum:[{}]", ViewConfig.exceptionQuestionTotalNum.get());
            recordMapper.updateById(record);

            //同意暂停说明这次测评结束了，不需要再推送数据了
            RoomBean roomBean = getRoomBean(mediaSuspendUuid);
            //关闭流媒体、通知算法结束
            try {
                evaluationService.endEvaluation(roomBean);
            } catch (InterruptedException e) {
                log.error("webSocket暂停测评通知流媒体算法异常");
            }
            // 发送消息给主副屏
            WebSocket.sendInfo(writeNullValue(msgObj));
        }
    }

    /**
     * @Description: 主屏拒绝暂停测评
     * @Author: Muqs
     * @Param: msgObj
     * @Date: 2021/8/27
     */
    private void disagreeSuspend(JSONObject msgObj) {
        JSONObject dataObj = msgObj.getJSONObject("data");
        if (dataObj != null) {
            // 发送消息给主副屏
            WebSocket.sendInfo(writeNullValue(msgObj));
        }
    }

    /**
     * @Description: 结束测评
     * @Author: Muqs
     * @Param: msgObj
     * @Date: 2021/8/27
     */
    private void submitAnswer(JSONObject msgObj) {
        // 将回答问题信息入库,如果存在则进行更新操作
        JSONObject dataObj = msgObj.getJSONObject("data");

        if (dataObj != null) {
            // 流媒体唯一标识uuid
            String uuid = dataObj.getString("uuid");
            // 答题记录ID
            Long recordId = dataObj.getLong("recordId");
            // 试题编号
            Integer answerQuestionNum = dataObj.getInteger("questionNum"); //2
            // 被测评人选择的试题答案
            String answerType = dataObj.getString("answerType");
            // 最后一题答题时常
            Integer answerTime = dataObj.getInteger("answerTime");
            log.info("提交answerTime:[{}]", answerTime);

            Record record = recordMapper.selectById(recordId);
            log.info("提交recordId:[{}]", recordId);
            log.info("提交record:[{}]", record);

            //achen 更新问题和折线图的数据
            //数据库录入问题折线图数据
            String questLineString = stringRedisTemplate.opsForValue().get(record.getRecordUuid() + "_question");
            log.info("questLineString:[{}]", questLineString);
            record.setQuestionLine(questLineString);
            //数据库录入时间折线图数据
            String timeLineString = stringRedisTemplate.opsForValue().get(record.getRecordUuid() + "_time");
            log.info("timeLineString:[{}]", timeLineString);
            record.setTimeLine(timeLineString);

            //更新异常表情次数和异常答题数
            log.info("ViewConfig.exceptionEmotionTotalNum:[{}]", ViewConfig.exceptionEmotionTotalNum.get());
            record.setExceptionSumNum(ViewConfig.exceptionEmotionTotalNum.get());

            log.info("ViewConfig.exceptionQuestionTotalNum:[{}]", ViewConfig.exceptionQuestionTotalNum.get());
            record.setExceptionQuestionSumNum(ViewConfig.exceptionQuestionTotalNum.get());

            // 如果有答题信息，则将答题信息更新保存，否则新增答题信息
            QueryWrapper answerWrapper = new QueryWrapper();
            answerWrapper.eq("answer_question_num", answerQuestionNum);
            answerWrapper.eq("record_id_fk", recordId);
            //最后一题
            Answer answer = answerMapper.selectOne(answerWrapper);
            log.info("结束测评answer-start:[{}]", answer);
            Project project = projectMapper.selectById(1L);

            if (answer == null) {
                answer = new Answer();
                answer.setAnswerQuestionNum(answerQuestionNum);
                answer.setAnswerType(answerType);
                answer.setRecordIdFk(recordId);
                answer.setScaleIdFk(record.getScaleIdFk());

                // 获取题目信息
                Map condition = new HashMap();
                condition.put("questionNum", answerQuestionNum);
                condition.put("scaleId", record.getScaleIdFk());
                QuestionVo questionVo = questionMapper.queryDetailById(condition);
                if (questionVo != null) {
                    answer.setQuestionIdFk(questionVo.getQuestionId());
                }
                answer.setRecordUuidFk(record.getRecordUuid());

                //是否为异常答题
                //todo
                //JSONArray jsonArray = JSON.parseArray(questLineString);
                //Integer everyMinuteExceptionNum = jsonArray.getJSONObject(jsonArray.size() - 1).getInteger("everyMinuteExceptionNum");
                //if (everyMinuteExceptionNum > 0) {
                if (ViewConfig.everyQuestionExceptionNum.get() > 0) {
                    answer.setAnswerException(0);
                } else {
                    answer.setAnswerException(1);
                }
                log.info("结束测评ViewConfig.everyQuestionExceptionNum.get():[{}]", ViewConfig.everyQuestionExceptionNum.get());

                //异常答题个数
                answer.setAnswerExceptionNum(ViewConfig.everyQuestionExceptionNum.get());
                //保存本道题最高异常值
                if (!CollectionUtils.isEmpty(AbnormalEmotionImage.abnormalEmotionList)) {
                    AbnormalEmotion abnormalEmotion = AbnormalEmotionImage.abnormalEmotionList.get(0);
                    answer.setAnswerExceptionMaxScore(abnormalEmotion.getImageScore());
                } else {
                    answer.setAnswerExceptionMaxScore(0);
                }
                //异常图片
                List<AbnormalEmotion> abnormalEmotionList = AbnormalEmotionImage.abnormalEmotionList;
                if (!CollectionUtils.isEmpty(abnormalEmotionList)) {
                    answer.setImageUrl(JSON.toJSONString(abnormalEmotionList));
                }
                AbnormalEmotionImage.abnormalEmotionList.clear();  // 清空数据
            }

            //是否为时间异常题目
            //不是时间异常题目 12
            if (answerTime >= (project.getTimeDown())*1000 && answerTime <= (project.getTimeUp())*1000) {
                answer.setAnswerExceptionTime(1);
            } else {
                answer.setAnswerExceptionTime(0);
            }

            answer.setAnswerType(answerType);
            answer.setAnswerTime(answerTime);
            if (answer.getAnswerId() == null) {
                answerMapper.insert(answer);
            } else {
                answerMapper.updateById(answer);
            }
            log.info("结束测评answer-end:[{}]", answer);

            record.setQuestionNum(answerQuestionNum);
            record.setStatus(1);
            record.setRecordEndTime(new Date());

            // 结束测评，将结束测评时间入库
            record.setRecordCreateTime(record.getRecordCreateTime() + "、" + sdf.format(new Date()));
            recordMapper.updateById(record);

            //  结束测评生成测评报告
            createReport(record.getScaleIdFk(), recordId);

            //by achen
            //关闭流媒体
            RoomBean roomBean = new RoomBean();
            roomBean.setUuid(uuid);
            try {
                evaluationService.endEvaluation(roomBean);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 发送消息给主副屏
            WebSocket.sendInfo(writeNullValue(msgObj));
        }
    }

    /**
     * @Description: 拍照上传之前推送流
     * @Author: achen
     * @Date: 2021/8/29
     */
    private void mediaStart(JSONObject msgObj) {

        if (null != ViewConfig.mediaStartCacheUuid) {
            mediaService.delSteam(ViewConfig.mediaStartCacheUuid);
            mediaService.stopUsbStream();
        }

        String uuid = UUID.randomUUID().toString();
        ViewConfig.mediaStartCacheUuid = uuid;


        RoomBean roomBean = new RoomBean();
        roomBean.setUuid(uuid);
        roomBean.setCameraUrl(cameraUrl);

        //调用流媒体接口 开启流媒体流 false标识不启用算法
        evaluationService.startEvaluation(roomBean, false);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("uuid", uuid);
        //rtsp流转换为.flv
        jsonObject.put("cameraUrl", FaceController.flvMethod(uuid, mediaIp, flvPort));
        log.info("writeNullValue(jsonObject):[{}]", writeNullValue(jsonObject));

        msgObj.put("data", jsonObject);

        // 发送消息给主屏，把流数据推送到前台
        if (WebSocket.getMainSession() != null) {
            WebSocket.SendMessage(WebSocket.getMainSession(), writeNullValue(msgObj));
        }
    }

    /**
     * @Description: 退出
     * @Author: muqs
     * @Param: msgObj
     * @Date: 2021/8/29
     */
    private void mainExit(JSONObject msgObj) {
        // 发送消息给主副屏
        WebSocket.sendInfo(writeNullValue(msgObj));
    }

    private static String writeNullValue(JSONObject jsonObject) {
        return JSONObject.toJSONString(jsonObject, SerializerFeature.WriteMapNullValue);
    }

    /**
     * 问题折线图推送
     */
    /*private List<QuestionLine> questionLine(String recordUuid, Integer questionNum, Integer preQuestNum) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(recordUuid);
        stringBuilder.append("_question");
        if (preQuestNum >1){
            String prevEveryExceptionNum = (String) stringRedisTemplate.opsForHash().get(stringBuilder.toString(), String.valueOf(preQuestNum));
            ViewConfig.everyQuestionExceptionNum.getAndAdd(Integer.parseInt(prevEveryExceptionNum));
            stringRedisTemplate.opsForHash().put(stringBuilder.toString(), String.valueOf(preQuestNum), String.valueOf(ViewConfig.everyQuestionExceptionNum.get()));
        }else{
            //去redis中查询对应测评记录下的题号对应的异常表情次数
            //参数1:测评记录uuid 参数2:题号

            String everyExceptionNum = (String) stringRedisTemplate.opsForHash().get(stringBuilder.toString(), String.valueOf(questionNum));
            //接收到是下一个题目之后
            if (StringUtils.isEmpty(everyExceptionNum)) {
                //如果不存在,说明第一次添加,将ViewConfig.everyExceptionNum置为0
                ViewConfig.everyQuestionExceptionNum.set(0);
            } else {
                //如果redis中存在,将ViewConfig.everyExceptionNum置为everyExceptionNum
                ViewConfig.everyQuestionExceptionNum.getAndAdd(Integer.parseInt(everyExceptionNum));
            }
            log.info("everyExceptionNum:[{}]", ViewConfig.everyQuestionExceptionNum.get());

            //点击下一题 参数1:测评记录uuid 参数2:题号 参数三:异常表情次数
            stringRedisTemplate.opsForHash().put(stringBuilder.toString(), String.valueOf(questionNum), String.valueOf(ViewConfig.everyQuestionExceptionNum.get()));
        }

        //通过webSocket推送给前台折题目线图的信息
        QuestionLine questionLine = null;
        List<QuestionLine> questionLines = new ArrayList<>();
        for (int i = 1; i <= questionNum; i++) {
            questionLine = new QuestionLine();
            //去redis根据测评记录的uuid查询出所有的题号跟异常表情次数
            stringRedisTemplate.opsForHash().get(recordUuid, String.valueOf(questionNum)); //2
            questionLine.setQuestionIndex(i);
            String exceptionFaceNum = (String) stringRedisTemplate.opsForHash().get(stringBuilder.toString(), String.valueOf(i));
            questionLine.setExceptionFaceNum(Integer.parseInt(exceptionFaceNum));
            questionLines.add(questionLine);
        }
        return questionLines;
    }*/

    /**
     * 发送题目维度的数据
     *
     * @param recordUuid
     * @param questionNum
     * @param sameQuestionFlag
     */
    public synchronized void sendQuestionLineException(String recordUuid, Integer questionNum, boolean sameQuestionFlag, Answer answer) {
        log.info("--------------------------------------------");
        log.info("题目维度questionNum:[{}]", questionNum);
        log.info("题目维度recordUuid参数:[{}]", recordUuid);

        //recordId
        log.info("ViewConfig.recordId:[{}]", ViewConfig.recordId);
        Record record = recordMapper.selectById(ViewConfig.recordId);
        log.info("题目维度record:[{}]", record);
        //log.info("题目维度record.getRecordUuid:[{}]", record.getRecordUuid());

        String questLineString = null;
        if (StringUtils.isEmpty(record.getRecordUuid())) {

            questLineString = stringRedisTemplate.opsForValue().get(recordUuid + "_question");
        } else {

            questLineString = stringRedisTemplate.opsForValue().get(record.getRecordUuid() + "_question");
        }
        // 从第一题开始
        JSONArray jsonArray = null;
        // 从第一题开始
        if (StringUtils.isNotEmpty(questLineString)) {
            jsonArray = JSON.parseArray(questLineString);
        } else {
            jsonArray = new JSONArray();
        }
        log.info("题目jsonArray:[{}]", jsonArray);
/*
//        JSONObject jsonObject = null;
//        for(int i = 0; i < jsonArray.size(); i++) {
//            if(jsonArray.getJSONObject(i).getInteger("questionIndex").equals(questionNum)) {
//                jsonObject = jsonArray.getJSONObject(i);
//            }
//        }
//
//        if(null != jsonObject) {
//            jsonObject.put("exceptionFaceNum", ViewConfig.everyQuestionExceptionNum.get());
//        }else {
//            JSONObject newJSON = new JSONObject();
//            newJSON.put("questionIndex", questionNum);
//            newJSON.put("exceptionFaceNum", ViewConfig.everyQuestionExceptionNum.get());
//            jsonArray.add(newJSON);
//        }
//
//        stringRedisTemplate.opsForValue().set(recordUuid + "_question", JSONArray.toJSONString(jsonArray, SerializerFeature.WriteMapNullValue));
//        log.info("question line [{}]", JSONArray.toJSONString(jsonArray));
//
//        //当是下一分钟的时候推前一分钟的异常表情次数
//        Map<String, Object> questLineMap = new HashMap<>();
//        questLineMap.put("type", "quest-line");
//        questLineMap.put("data", jsonArray);
//        if (WebSocket.getMainSession() != null) {
//            WebSocket.SendMessage(WebSocket.getMainSession(), JSONObject.toJSONString(questLineMap, SerializerFeature.WriteMapNullValue));
//        }
//
//        ViewConfig.everyQuestionExceptionNum.set(0);
*/
        // 不是同一题 add
        if (CollectionUtils.isEmpty(jsonArray)) {
            JSONObject newJson = new JSONObject();
            newJson.put("questionIndex", questionNum);
            newJson.put("exceptionFaceNum", ViewConfig.everyQuestionExceptionNum.get());
            jsonArray.add(newJson);
        } else {
            JSONObject jsonObject = null;
            for (int i = 0; i < jsonArray.size(); i++) {
                log.info("题目维度jsonArray.getJSONObject(i).getInteger('questionIndex').equals(questionNum):[{}]", jsonArray.getJSONObject(i).getInteger("questionIndex").equals(questionNum));
                if (jsonArray.getJSONObject(i).getInteger("questionIndex").equals(questionNum)) {
                    jsonObject = jsonArray.getJSONObject(i);
                }
            }
            if (null != jsonObject) {
                //ViewConfig.everyQuestionExceptionNum.set(ViewConfig.everyQuestionExceptionNum.get() + jsonObject.getIntValue("exceptionFaceNum"));
                jsonObject.put("exceptionFaceNum", ViewConfig.everyQuestionExceptionNum.get()); //0
            } else {
                jsonObject = new JSONObject();
                jsonObject.put("questionIndex", questionNum);
                jsonObject.put("exceptionFaceNum", ViewConfig.everyQuestionExceptionNum.get());
                jsonArray.add(jsonObject);
            }
        }

        //更新每一题的异常表情次数
        if (answer != null) {
            if (ViewConfig.everyQuestionExceptionNum.get() > 0) {
                answer.setAnswerException(0);
            } else {
                answer.setAnswerException(1);
            }
            //更新每道题的异常表情次数
            answer.setAnswerExceptionNum(ViewConfig.everyQuestionExceptionNum.get());
            answerMapper.updateById(answer);
        }

        stringRedisTemplate.opsForValue().set(recordUuid + "_question", JSONArray.toJSONString(jsonArray, SerializerFeature.WriteMapNullValue));
        log.info("question line ------------------------------ &&&& [{}]", JSONArray.toJSONString(jsonArray, SerializerFeature.WriteMapNullValue));

        //当是下一分钟的时候推前一分钟的异常表情次数
        Map<String, Object> questLineMap = new HashMap<>();
        questLineMap.put("type", "quest-line");
        //添加继续测评的数据
        //questJSONArray.addAll(jsonArray);
        questLineMap.put("data", jsonArray);
        if (WebSocket.getMainSession() != null) {
            WebSocket.SendMessage(WebSocket.getMainSession(), JSONObject.toJSONString(questLineMap, SerializerFeature.WriteMapNullValue));
        }
        if (!sameQuestionFlag) {
            //答题题号
            ViewConfig.currentQuestIndex.set(questionNum);
            ViewConfig.everyQuestionExceptionNum.set(0);
        }
    }


    /**
     * 发送时间维度异常数据
     */
    public void sendTimeLineException(String recordUuid, boolean sameMinuteFlag) {
        log.info("************************时间折线图recordUuid:[{}]", recordUuid);
        //从第一分钟开始
        JSONArray jsonArray = new JSONArray();
        String timeLineString = stringRedisTemplate.opsForValue().get(recordUuid + "_time");
        log.info("************************时间折线图timeLineString:[{}]", timeLineString);
        if (StringUtils.isNotEmpty(timeLineString)) {
            jsonArray = JSONArray.parseArray(timeLineString);
        }
        // 不是同一分钟 add
        if (jsonArray.size() == 0) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("minuteNum", ViewConfig.minuteNum.get() == 0 ? 1 : ViewConfig.minuteNum.get());
            jsonObject.put("everyMinuteExceptionNum", ViewConfig.everyMinuteExceptionNum.get());
            jsonArray.add(jsonObject);
        } else {

            if (!sameMinuteFlag) {   // 实时计算
                if (ViewConfig.minuteNum.get() == 1) {
                    JSONObject jsonObject = jsonArray.getJSONObject(0);
                    if (null != jsonObject) {
                        /**
                         * 这是新加的
                         */
                        ViewConfig.everyMinuteExceptionNum.getAndSet(jsonObject.getIntValue("everyMinuteExceptionNum"));
                        jsonObject.put("everyMinuteExceptionNum", ViewConfig.everyMinuteExceptionNum.get());
                    }
                } else {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("minuteNum", ViewConfig.minuteNum.get());
                    jsonObject.put("everyMinuteExceptionNum", ViewConfig.everyMinuteExceptionNum.get());
                    jsonArray.add(jsonObject);
                }

            } else {
                JSONObject jsonObject = jsonArray.getJSONObject(jsonArray.size() - 1);
                if (null != jsonObject) {
                    jsonObject.put("everyMinuteExceptionNum", ViewConfig.everyMinuteExceptionNum.get());
                }
            }
        }


//        if (!sameMinuteFlag || jsonArray.size() == 0) {
//            JSONObject jsonObject = new JSONObject();
//            if(sameMinuteFlag) {
//                jsonObject.put("minuteNum", ViewConfig.minuteNum.get() == 0 ? 1 : ViewConfig.minuteNum.get());
//            }else {
//
//
//                jsonObject.put("minuteNum", ViewConfig.minuteNum.get());
//            }
//            jsonObject.put("everyMinuteExceptionNum", ViewConfig.everyMinuteExceptionNum.get());
//            jsonArray.add(jsonObject);
//        } else {
//            JSONObject jsonObject = jsonArray.getJSONObject(jsonArray.size() - 1);
//            if (null != jsonObject) {
//                //jsonObject.put("minuteNum", ViewConfig.minuteNum.get());
//                jsonObject.put("everyMinuteExceptionNum", ViewConfig.everyMinuteExceptionNum.get());
//            }
//        }

        //log.info("JSONArray:[{}]", JSONArray.toJSONString(jsonArray));
        stringRedisTemplate.opsForValue().set(recordUuid + "_time", JSONArray.toJSONString(jsonArray, SerializerFeature.WriteMapNullValue));

        //当是下一分钟的时候推前一分钟的异常表情次数
        Map<String, Object> timeLineMap = new HashMap<>();
        timeLineMap.put("type", "time-line");
        //添加继续测评的数据
        //log.info("时间折线图timeJSONArray:[{}]", timeJSONArray);
//        jsonArray.addAll(timeJSONArray);
//        //转换为list
//        List<JSONObject> jsonObjectList = JSONArray.parseArray(jsonArray.toJSONString(), JSONObject.class);
//        //根据时间排序
//        Collections.sort(jsonObjectList, (o1, o2) -> {
//            return o1.getInteger("minuteNum") - o2.getInteger("minuteNum");
//        });
        timeLineMap.put("data", jsonArray);
        if (WebSocket.getMainSession() != null) {
            WebSocket.SendMessage(WebSocket.getMainSession(), JSONObject.toJSONString(timeLineMap, SerializerFeature.WriteMapNullValue));
        }
    }

    /**
     * 人脸识别
     */
    public void faceRecognition(JSONObject msgObj) {
        if (null != ViewConfig.mediaStartCacheUuid) {
            mediaService.delSteam(ViewConfig.mediaStartCacheUuid);
            mediaService.stopUsbStream();
        }

        //JSONObject data = msgObj.getJSONObject("data");
        //uuid
        String uuid = UUID.randomUUID().toString();
        //String uuid = ApplicationRunnerImpl.algUuid;
        ViewConfig.mediaStartCacheUuid = uuid;

        //流媒体地址
        RoomBean roomBean = new RoomBean().setCameraUrl(cameraUrl).setUuid(uuid);

        //调用流媒体接口添加视频流
        evaluationService.startEvaluation(roomBean, false);

        JSONObject jsonObject = msgObj.getJSONObject("data");
        jsonObject.put("uuid", uuid);
        jsonObject.put("cameraUrl", FaceController.flvMethod(uuid, mediaIp, flvPort));

        //msgObj.put("data", jsonObject);

        //人脸识别
        new Thread(() -> {
            faceStartRecognition(msgObj, uuid);
        }).start();

        if (WebSocket.getMainSession() != null) {
            WebSocket.SendMessage(WebSocket.getMainSession(), writeNullValue(msgObj));
        }
    }

    /**
     * 人脸识别通知算法
     *
     * @param jObj
     */
    public void faceStartRecognition(JSONObject jObj, String uuid) {
        JSONObject data = jObj.getJSONObject("data");
        log.info("人脸识别算法data:[{}]", data);
        Boolean state = (Boolean) data.get("state");

        JSONObject jsonObject = new JSONObject();
        String jsonFace = null;
        //String algCameraUrl = "rtsp://192.168.100.128:8554/stream/" + uuid;
        String algCameraUrl = "rtsp://127.0.0.1:8554/live/" + uuid;
        log.info("人脸识别算法uuid：[{}]", uuid);
        jsonObject.put("url", algCameraUrl);
        log.info("算法cameraUrl:[{}]", algCameraUrl);
        jsonObject.put("state", state);
        log.info("人脸识别算法state:[{}]", state);

        //人脸识别没有结束
        if (state) {
            jsonObject.put("uid", algUuid);
            jsonFace = JSONObject.toJSONString(jsonObject);

            //mqtt通知算法人脸识别开始
            mqttCustomClient.publish(Constants.FACE_RECOGNITION_CONTROL, jsonFace);
            log.info("进入算法了");
        } else {
            //关闭流媒体
            mediaService.delSteam(ViewConfig.mediaStartCacheUuid);
            mediaService.stopUsbStream();

            //通知算法结束
            jsonObject.put("uid", algUuid);
            jsonFace = JSONObject.toJSONString(jsonObject);

            //通知算法人脸识别结束
            mqttCustomClient.publish(Constants.FACE_RECOGNITION_CONTROL, jsonFace);
        }
    }

    /**
     * 秒转换小时-分-秒
     *
     * @param seconds 秒为单位 比如..600秒
     * @return 比如...2小时3分钟52秒
     */
    private String secToTime(int seconds) {
        DecimalFormat df = new DecimalFormat("00");
        int hour = seconds / 3600;
        int minute = (seconds - hour * 3600) / 60;
        int second = (seconds - hour * 3600 - minute * 60);

        StringBuffer sb = new StringBuffer();
        sb.append(df.format(hour) + ":");
        sb.append(df.format(minute) + ":");
        sb.append(df.format(second));
        return sb.toString();
    }

    /**
     * @Description: 生成测评报告
     * @Param: scaleId
     * @Param: recordId
     * @Author: muqs
     * @Date: 2021/8/31
     */
    private void createReport(Long scaleId, Long recordId) {
        try {
            ReportVo reportVo = answerMapper.getReportReview(recordId);

            List<QuestionVo> questionList = questionMapper.queryByScaleId(scaleId);
            Map<String, Integer> optionScoreMap = new HashMap();
            if (!CollectionUtils.isEmpty(questionList)) {
                questionList.stream().forEach(item -> {
                    List<Option> options = item.getOptionList();
                    if (!CollectionUtils.isEmpty(options)) {
                        options.stream().forEach(option -> {
                            optionScoreMap.put(option.getQuestionIdFk() + "-" + option.getOptionType(), option.getOptionScore());
                        });
                    }
                });
            }

            if (reportVo != null) {
                List<AnswerVo> answerVos = reportVo.getAnswerVoList();

                Report report = new Report();
                // 报告综述对象
                JSONObject bgzsObj = new JSONObject();
                // 答题时常
                bgzsObj.put("dtsc", reportVo.getDtsc());
                // 题目总数
                bgzsObj.put("tmzs", reportVo.getTmzs());
                // 中断次数
                bgzsObj.put("zdcs", reportVo.getZdcs());
                // 测评开始时间
                bgzsObj.put("cpkssj", reportVo.getKscpsj());
                // 微表情题目数
                bgzsObj.put("wbqtms", reportVo.getAnswerVoList().size());

                // 获取表情异常值最高题目和分数
                //按异常分数升序排序(Integer类型)

                StringBuffer cpbgjlQuestionSb = new StringBuffer();

                if (!CollectionUtils.isEmpty(answerVos)) {
                    List<AnswerVo> answerMaxVos = answerVos.stream().sorted(Comparator.comparing(AnswerVo::getAnswerExceptionMaxScore).reversed()).collect(Collectors.toList());

                    if (!CollectionUtils.isEmpty(answerMaxVos)) {
                        AnswerVo maxAnswerVo = answerMaxVos.get(0);
                        bgzsObj.put("wbqyczzgtm", maxAnswerVo.getAnswerQuestionNum());
                        bgzsObj.put("wbqyczzgf", maxAnswerVo.getAnswerExceptionMaxScore());
                    }

                    // 拼接测评结论题目数据信息
                    cpbgjlQuestionSb.append("其中全部的" + answerVos.size() + "道题目中，有" + answerVos.size() + "道题目存在微表情异常，分别为");

                    // 异常题目编号
                    StringBuffer yctmbhSb = new StringBuffer();

                    for (int i = 0; i < answerVos.size(); i++) {
                        AnswerVo answerVo = answerVos.get(i);
                        if (Integer.valueOf(i).equals(Integer.valueOf(answerVos.size() - 1))) {
                            yctmbhSb.append("第" + answerVo.getAnswerQuestionNum() + "道题");
                            cpbgjlQuestionSb.append("第" + answerVo.getAnswerQuestionNum() + "道题目得" + optionScoreMap.get(answerVo.getQuestionIdFk() + "-" + answerVo.getAnswerType()) + "分。");
                        } else {
                            yctmbhSb.append("第" + answerVo.getAnswerQuestionNum() + "道题").append("、");
                            cpbgjlQuestionSb.append("第" + answerVo.getAnswerQuestionNum() + "道题目得" + optionScoreMap.get(answerVo.getQuestionIdFk() + "-" + answerVo.getAnswerType()) + "分，");
                        }
                    }
                    bgzsObj.put("yctmbh", yctmbhSb.toString());
                }

                report.setReportContent(JSONObject.toJSONString(bgzsObj));
                report.setExceptionNum(reportVo.getYctmsl());
                report.setRecordIdFk(recordId);
                report.setTesteeIdFk(scaleId);
                //异常题目总数
                //report.setExceptionNum(ViewConfig.exceptionQuestionNum);

                // 测评报告结论
                String cpbgjl = "被测人{0}在《{1}》的测评中总评分为{2}，{3}";

                // 获取测评分数
                String score = answerMapper.getScore(recordId);

                // 根据测评分数获取测评结果;
                Map param = new HashMap();
                param.put("scaleId", scaleId);
                param.put("score", score);
                Score scoreResult = scoreMapper.queryScoreContent(param);

                RecordVo recordVo = recordMapper.queryRecordDetailById(recordId);
                if (recordVo != null) {
                    Object[] array = new Object[]{recordVo.getRecordTesteeName(), recordVo.getScaleName(), score, scoreResult != null ? scoreResult.getScoreContent() : "不存在心里健康问题"};
                    String msg = MessageFormat.format(cpbgjl, array);

                    if (StringUtils.isNotEmpty(cpbgjlQuestionSb.toString())) {
                        report.setConclusion(msg + "，" + cpbgjlQuestionSb.toString());
                    } else {
                        report.setConclusion(msg + "。");
                    }
                }

                reportMapper.insert(report);
            }
        } catch (Exception e) {
            log.error("创建测评报告异常,recordId:{},error:{}", recordId, e);
        }
    }

    /**
     * 获取RoomBean
     *
     * @param uuid
     * @return RoomBean
     */
    public RoomBean getRoomBean(String uuid) {
        RoomBean roomBean = new RoomBean();
        roomBean.setUuid(uuid);
        roomBean.setSsUrl(uuid);
        roomBean.setUserId("111");
        roomBean.setStreamWay(1);
        roomBean.setCameraUrl(cameraUrl);
        roomBean.setAudioUrl(cameraUrl);
        return roomBean;
    }

    /**
     * @Description: // 确认暂停，退出测评
     * @Param: msgObj
     * @Author: muqs
     * @Date: 2021/8/27
     */
    private void exitEvaluation(JSONObject msgObj) {
        // 发送消息给主副屏
        WebSocket.sendInfo(writeNullValue(msgObj));
    }

    /**
     * 转换rtsp为flv
     *
     * @param uuid
     */
    public String flvMethod(String uuid, String mediaIp, Integer flvPort) {
        //cameraUrl:http://192.168.16.166:7070/live/e8b7f55e-f075-4b60-95a7-e48fbcee86bb.flv 前台需要根据.flv播放视频
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("http://");
        stringBuilder.append(mediaIp);
        stringBuilder.append(":");
        stringBuilder.append(flvPort);
        stringBuilder.append("/" + usbType + "/");
        stringBuilder.append(uuid);
        stringBuilder.append(".flv");
        return stringBuilder.toString();
    }
}
